﻿using MetaProperties.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MetaProperties.Framework;
using System.Collections.Generic;
using System;
using System.ComponentModel;

namespace MetaProperties.Core.Tests
{
    /// <summary>
    ///This is a test class for MetaPropertyTest and is intended
    ///to contain all MetaPropertyTest Unit Tests
    ///</summary>
    [TestClass()]
    public class MetaPropertyTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for Value
        ///</summary>
        public void ValueTestHelper<T>(T value)
        {
            var container = new Observable<T>(value);
            MetaProperty<T> target = new MetaProperty<T>(container);
            Assert.AreEqual(value, target.Value);
        }

        [TestMethod()]
        public void ValueTest()
        {
            ValueTestHelper<GenericParameterHelper>(new GenericParameterHelper(5));
        }

        /// <summary>
        ///A test for PropertyType
        ///</summary>
        public void PropertyTypeTest1Helper<T>()
        {
            var container = new Observable<T>();
            MetaProperty<T> target = new MetaProperty<T>(container);
            Assert.AreEqual(typeof(T), target.PropertyType);
        }

        [TestMethod()]
        public void PropertyTypeTest1()
        {
            PropertyTypeTest1Helper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Container_ValueSet
        ///</summary>
        public void Container_ValueSetTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            MetaProperty<T> metaProperty = new MetaProperty<T>(notifying);
            PrivateObject param0 = new PrivateObject(metaProperty);
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            object sender = null;
            ValueChangedEventArgs<T> e = new ValueChangedEventArgs<T>(
                default(T), default(T));

            bool eventCalled = false;
            metaProperty.ValueSet += (s, args) =>
                {
                    eventCalled = true;
                    Assert.AreEqual(metaProperty, s);
                };

            target.Container_ValueSet(sender, e);

            Assert.IsTrue(eventCalled);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void Container_ValueSetTest()
        {
            Container_ValueSetTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Container_ValueChanged
        ///</summary>
        public void Container_ValueChangedTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            MetaProperty<T> metaProperty = new MetaProperty<T>(notifying);
            PrivateObject param0 = new PrivateObject(metaProperty);
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            object sender = null;
            ValueChangedEventArgs<T> e = new ValueChangedEventArgs<T>(default(T), default(T));

            bool eventCalled = false;
            metaProperty.ValueChanged += (s, args) =>
            {
                eventCalled = true;
                Assert.AreEqual(metaProperty, s);
            };

            target.Container_ValueChanged(sender, e);

            Assert.IsTrue(eventCalled);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void Container_ValueChangedTest()
        {
            Container_ValueChangedTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Container_UntypedValueSet
        ///</summary>
        public void Container_UntypedValueSetTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            MetaProperty<T> metaProperty = new MetaProperty<T>(notifying);
            PrivateObject param0 = new PrivateObject(metaProperty);
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            object sender = null;
            ValueChangedEventArgs<T> e = new ValueChangedEventArgs<T>(default(T), default(T));

            bool eventCalled = false;
            metaProperty.UntypedValueSet += (s, args) =>
            {
                eventCalled = true;
                Assert.AreEqual(metaProperty, s);
            };

            target.Container_UntypedValueSet(sender, e);

            Assert.IsTrue(eventCalled);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void Container_UntypedValueSetTest()
        {
            Container_UntypedValueSetTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Container_UntypedValueChanged
        ///</summary>
        public void Container_UntypedValueChangedTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            MetaProperty<T> metaProperty = new MetaProperty<T>(notifying);
            PrivateObject param0 = new PrivateObject(metaProperty);
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            object sender = null;
            ValueChangedEventArgs<T> e = new ValueChangedEventArgs<T>(default(T), default(T));

            bool eventCalled = false;
            metaProperty.UntypedValueChanged += (s, args) =>
            {
                eventCalled = true;
                Assert.AreEqual(metaProperty, s);
            };

            target.Container_UntypedValueChanged(sender, e);

            Assert.IsTrue(eventCalled);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void Container_UntypedValueChangedTest()
        {
            Container_UntypedValueChangedTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Container_PropertyChanging
        ///</summary>
        public void Container_PropertyChangingTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            MetaProperty<T> metaProperty = new MetaProperty<T>(notifying);
            PrivateObject param0 = new PrivateObject(metaProperty);
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            object sender = null;
            PropertyChangingEventArgs e = new PropertyChangingEventArgs("TestProperty");

            bool eventCalled = false;
            metaProperty.PropertyChanging += (s, args) =>
            {
                eventCalled = true;
                Assert.AreEqual(metaProperty, s);
            };

            target.Container_PropertyChanging(sender, e);

            Assert.IsTrue(eventCalled);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void Container_PropertyChangingTest()
        {
            Container_PropertyChangingTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Container_PropertyChanged
        ///</summary>
        public void Container_PropertyChangedTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            MetaProperty<T> metaProperty = new MetaProperty<T>(notifying);
            PrivateObject param0 = new PrivateObject(metaProperty);
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            object sender = null;
            PropertyChangedEventArgs e = new PropertyChangedEventArgs("TestProperty");

            bool eventCalled = false;
            metaProperty.PropertyChanged += (s, args) =>
            {
                eventCalled = true;
                Assert.AreEqual(metaProperty, s);
            };

            target.Container_PropertyChanged(sender, e);

            Assert.IsTrue(eventCalled);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void Container_PropertyChangedTest()
        {
            Container_PropertyChangedTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for MetaProperty`1 Constructor
        ///</summary>
        public void MetaPropertyConstructorTestHelper<T>(T value)
        {
            var container = new Observable<T>(value);
            MetaProperty<T> target = new MetaProperty<T>(container);
            Assert.AreEqual(container.Value, target.Value);
        }

        [TestMethod()]
        public void MetaPropertyConstructorTest()
        {
            MetaPropertyConstructorTestHelper<GenericParameterHelper>(new GenericParameterHelper(5));
        }

        /// <summary>
        ///A test for MetaProperty`1 Constructor
        ///</summary>
        public void MetaPropertyConstructor1TestHelper<T>()
        {
            MetaProperty<T> target = new MetaProperty<T>(null);
        }

        [TestMethod()]
        [ExpectedException(typeof(ArgumentNullException), "container")]
        public void MetaPropertyConstructor1Test()
        {
            MetaPropertyConstructor1TestHelper<GenericParameterHelper>();
        }
        
        /// <summary>
        ///A test for UntypedValue
        ///</summary>
        [TestMethod()]
        public void UntypedValueTest()
        {
            Observable<GenericParameterHelper> notifying = new Observable<GenericParameterHelper>(new GenericParameterHelper(5));
            MetaProperty target = new MetaProperty<GenericParameterHelper>(notifying);

            Assert.AreEqual(notifying.Value, target.UntypedValue);
        }

        /// <summary>
        ///A test for PropertyType
        ///</summary>
        [TestMethod()]
        public void PropertyTypeTest()
        {
            Observable<GenericParameterHelper> notifying = new Observable<GenericParameterHelper>(new GenericParameterHelper(5));
            MetaProperty target = new MetaProperty<GenericParameterHelper>(notifying);

            Assert.AreEqual(typeof(GenericParameterHelper), target.PropertyType);
        }

        /// <summary>
        ///A test for PropertyName
        ///</summary>
        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void PropertyNameTest()
        {
            Observable<GenericParameterHelper> container = new Observable<GenericParameterHelper>();
            MetaProperty<GenericParameterHelper> metaProperty = new MetaProperty<GenericParameterHelper>(container);
            PrivateObject param0 = new PrivateObject(metaProperty, new PrivateType(typeof(MetaProperty)));
            MetaProperty_Accessor target = new MetaProperty_Accessor(param0);

            string expected = "Test";
            string actual;

            target.PropertyName = expected;
            actual = target.PropertyName;

            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for Host
        ///</summary>
        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void HostTest()
        {
            Observable<GenericParameterHelper> container = new Observable<GenericParameterHelper>();
            MetaProperty<GenericParameterHelper> metaProperty = new MetaProperty<GenericParameterHelper>(container);
            PrivateObject param0 = new PrivateObject(metaProperty, new PrivateType(typeof(MetaProperty)));
            MetaProperty_Accessor target = new MetaProperty_Accessor(param0);

            object expected = new object();
            object actual;
            target.Host = expected;
            actual = target.Host;

            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for Initialize
        ///</summary>
        [TestMethod()]
        public void InitializeTest()
        {
            Observable<GenericParameterHelper> container = new Observable<GenericParameterHelper>();
            MetaProperty target = new MetaProperty<GenericParameterHelper>(container);
            MetaProperty_Accessor accessor = new MetaProperty_Accessor(new PrivateObject(target, new PrivateType(typeof(MetaProperty<GenericParameterHelper>))));

            MetaPropertyConfiguration initializationInfo = new MetaPropertyConfiguration(
                this, 
                "Test", 
                new SetEventFilterAttribute(typeof(TestEventFilter)));

            target.Initialize(initializationInfo);

            Assert.AreEqual(this, target.Host);
            Assert.AreEqual(1, accessor.Filters.Count);
            Assert.AreEqual("Test", target.PropertyName);
        }

        private class TestEventFilter : IEventFilter
        {
            public void SetMetaPropertyConfiguration(MetaPropertyConfiguration configuration)
            {
                
            }

            public void PerformFilter(object sender, EventArgs args, IFilterPipeline pipeline)
            {
            }
        }

        /// <summary>
        ///A test for ExecuteValueChangedDelegate
        ///</summary>
        public void ExecuteValueChangedDelegateTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            PrivateObject param0 = new PrivateObject(notifying.MetaProperty, new PrivateType(typeof(MetaProperty<T>)));
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            bool isExecuted = false;

            object sender = this;
            EventArgs args = new ValueChangedEventArgs<T>(default(T), default(T));
            Delegate d = new ValueChangedEventHandler<T>((s, e) =>
                {
                    isExecuted = true;
                    Assert.AreEqual(sender, s);
                    Assert.AreEqual(args, e);
                });
            target.ExecuteValueChangedDelegate(sender, args, d);

            Assert.IsTrue(isExecuted);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void ExecuteValueChangedDelegateTest()
        {
            ExecuteValueChangedDelegateTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for ExecuteUntypedValueChangedDelegate
        ///</summary>
        public void ExecuteUntypedValueChangedDelegateTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            PrivateObject param0 = new PrivateObject(notifying.MetaProperty, new PrivateType(typeof(MetaProperty<T>)));
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            bool isExecuted = false;

            object sender = this;
            EventArgs args = new ValueChangedEventArgs<T>(default(T), default(T));
            Delegate d = new ValueChangedEventHandler((s, e) =>
            {
                isExecuted = true;
                Assert.AreEqual(sender, s);
                Assert.AreEqual(args, e);
            });
            target.ExecuteUntypedValueChangedDelegate(sender, args, d);

            Assert.IsTrue(isExecuted);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void ExecuteUntypedValueChangedDelegateTest()
        {
            ExecuteUntypedValueChangedDelegateTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for ExecutePropertyChangingDelegate
        ///</summary>
        public void ExecutePropertyChangingDelegateTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            PrivateObject param0 = new PrivateObject(notifying.MetaProperty, new PrivateType(typeof(MetaProperty<T>)));
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            bool isExecuted = false;

            object sender = this;
            EventArgs args = new PropertyChangingEventArgs("Value");
            Delegate d = new PropertyChangingEventHandler((s, e) =>
            {
                isExecuted = true;
                Assert.AreEqual(sender, s);
                Assert.AreEqual(args, e);
            });
            target.ExecutePropertyChangingDelegate(sender, args, d);

            Assert.IsTrue(isExecuted);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void ExecutePropertyChangingDelegateTest()
        {
            ExecutePropertyChangingDelegateTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for ExecutePropertyChangedDelegate
        ///</summary>
        public void ExecutePropertyChangedDelegateTestHelper<T>()
        {
            Observable<T> notifying = new Observable<T>();
            PrivateObject param0 = new PrivateObject(notifying.MetaProperty, new PrivateType(typeof(MetaProperty<T>)));
            MetaProperty_Accessor<T> target = new MetaProperty_Accessor<T>(param0);

            bool isExecuted = false;

            object sender = this;
            EventArgs args = new PropertyChangedEventArgs("Value");
            Delegate d = new PropertyChangedEventHandler((s, e) =>
            {
                isExecuted = true;
                Assert.AreEqual(sender, s);
                Assert.AreEqual(args, e);
            });
            target.ExecutePropertyChangedDelegate(sender, args, d);

            Assert.IsTrue(isExecuted);
        }

        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void ExecutePropertyChangedDelegateTest()
        {
            ExecutePropertyChangedDelegateTestHelper<GenericParameterHelper>();
        }

        /// <summary>
        ///A test for Filters
        ///</summary>
        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void FiltersTest()
        {
            Observable<int> notifying = new Observable<int>();
            PrivateObject param0 = new PrivateObject(notifying.MetaProperty, new PrivateType(typeof(MetaProperty<int>)));
            MetaProperty_Accessor target = new MetaProperty_Accessor(param0);

            notifying.MetaProperty.Initialize(new MetaPropertyConfiguration(
                this,
                "Test",
                new SetEventFilterAttribute(typeof(TestFilter))));

            IList<IEventFilter> actual = target.Filters;

            Assert.IsNotNull(actual);
            Assert.AreEqual(1, actual.Count);
        }

        /// <summary>
        ///A test for FilterCount
        ///</summary>
        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void FilterCountTest()
        {
            Observable<int> notifying = new Observable<int>();
            PrivateObject param0 = new PrivateObject(notifying.MetaProperty, new PrivateType(typeof(MetaProperty<int>)));
            MetaProperty_Accessor target = new MetaProperty_Accessor(param0);

            notifying.MetaProperty.Initialize(new MetaPropertyConfiguration(
                this,
                "Test",
                new SetEventFilterAttribute(typeof(TestFilter))));

            int actual = target.FilterCount;

            Assert.AreEqual(1, actual);
        }

        private class TestFilter : IEventFilter
        {
            public void SetMetaPropertyConfiguration(MetaPropertyConfiguration configuration)
            {
                
            }

            public void PerformFilter(object sender, EventArgs args, IFilterPipeline pipeline)
            {
            }
        }
    }
}
